package com.example.server.plugins

import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import com.example.commons.models.LoginUser
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.auth.jwt.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.*

const val JWT_SECRET = "secret"
const val JWT_ISSUER = "http://0.0.0.0:8080/"
const val JWT_AUDIENCE = "http://0.0.0.0:8080/hello"

private val logger: Logger = LoggerFactory.getLogger("authentication")

/**
 * https://ktor.io/docs/jwt.html
 * https://ktor.io/docs/jwt.html#authenticate-route
 */
fun Application.configureSecurity() {

    authentication {
//        val s = this@configureSecurity.environment.config.tryGetString("jwt.realm")
//        println("realm = $s")

        jwt("auth-jwt") {
            realm = "Access to 'hello'"
            verifier(
                JWT
                    .require(Algorithm.HMAC256(JWT_SECRET))
                    .withAudience(JWT_AUDIENCE)
                    .withIssuer(JWT_ISSUER)
                    .build()
            )
            validate { credential ->
                logger.info("validate   ${request.local.uri}")
                logger.info(credential.toString())
//                val un = credential["username"]
//                if (un == "admin") {
//                    JWTPrincipal(credential.payload)
//                } else {
//                    null
//                }
//                credential.payload.getClaim("username").asString()
                if (credential.payload.audience.contains(JWT_AUDIENCE)) JWTPrincipal(credential.payload) else null
            }

            challenge { defaultScheme, realm ->
                call.respond(HttpStatusCode.Unauthorized, mapOf("msg" to "未授权"))
            }
        }

        provider("auth-custom") {
            authenticate {
                logger.info(it.principal.toString())
            }
        }

        basic("auth-basic") {
            validate {
                if (it.name == "admin" && it.password == "123456") {
                    UserIdPrincipal(it.name)
                } else {
                    null
                }
            }
        }

//        oauth("auth-oauth-google") {
//            urlProvider = { "http://localhost:8080/callback" }
//            providerLookup = {
//                OAuthServerSettings.OAuth2ServerSettings(
//                    name = "google",
//                    authorizeUrl = "https://accounts.google.com/o/oauth2/auth",
//                    accessTokenUrl = "https://accounts.google.com/o/oauth2/token",
//                    requestMethod = HttpMethod.Post,
//                    clientId = System.getenv("GOOGLE_CLIENT_ID"),
//                    clientSecret = System.getenv("GOOGLE_CLIENT_SECRET"),
//                    defaultScopes = listOf("https://www.googleapis.com/auth/userinfo.profile")
//                )
//            }
//            client = HttpClient(Apache)
//        }
    }

    routing {

        post("/login") {
            val u = call.receive<LoginUser>()

            val token = JWT.create()
                .withAudience(JWT_AUDIENCE)
                .withIssuer(JWT_ISSUER)
                .withClaim("username", u.username)
                .withExpiresAt(
                    Date.from(
                        LocalDateTime.now().plusDays(2).atZone(ZoneId.systemDefault()).toInstant()
                    )
                )
                .sign(Algorithm.HMAC256(JWT_SECRET))
            call.respond(hashMapOf("token" to token))
        }

//        authenticate("auth-oauth-google") {
//            get("login") {
//                call.respondRedirect("/callback")
//            }
//
//            get("/callback") {
//                val principal: OAuthAccessTokenResponse.OAuth2? = call.authentication.principal()
//                call.sessions.set(UserSession(principal?.accessToken.toString()))
//                call.respondRedirect("/hello")
//            }
//        }
    }
}

//class UserSession(accessToken: String)
